// HD44780 Controller instruction set http://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller
// Si RS OFF -> Commande, SI RS ON -> Donnee

// 4-bit Initialization:
// ! Valable si pin R/W force a 0 par cablage materiel
// LCD Control Pins
#include "stm32f4xx.h"
#include "commands_4bits.h"

#define E_ON   	GPIOC->BSRRL = 1<<1
#define E_OFF  	GPIOC->BSRRH = 1<<1
#define RS_ON  	GPIOC->BSRRL = 1<<2
#define RS_OFF 	GPIOC->BSRRH = 1<<2
// LCD Pins
#define LCD_DATA_PORT GPIOB
#define P4 11
#define P5 12
#define P6 13
#define P7 14
#define P4_ON 	GPIOB->BSRRL = 1<<11
#define P5_ON		GPIOB->BSRRL = 1<<12
#define P6_ON		GPIOB->BSRRL = 1<<13
#define P7_ON		GPIOB->BSRRL = 1<<14
#define P4_OFF 	GPIOB->BSRRH = 1<<11
#define P5_OFF	GPIOB->BSRRH = 1<<12
#define P6_OFF	GPIOB->BSRRH = 1<<13
#define P7_OFF	GPIOB->BSRRH = 1<<14

#define bit7 1<<7
#define bit6 1<<6
#define bit5 1<<5
#define bit4 1<<4

// Ecrit 1 caractere
void write_char(char car)
{
	RS_ON;	// donnee
	E_ON;		// arme
	if ( car & bit7 )
	  P7_ON;
	else
		P7_OFF;
	if ( car & bit6 )
	  P6_ON;
	else
		P6_OFF;
	if ( car & bit5 )
	  P5_ON;
	else
		P5_OFF;
	if ( car & bit4 )
	  P4_ON;
	else
		P4_OFF;	
	E_OFF;	// valide commande sur front descendant
	car = car<<4;
	E_ON; 	// arme
	if ( car & bit7 )
	  P7_ON;
	else
		P7_OFF;
	if ( car & bit6 )
	  P6_ON;
	else
		P6_OFF;
	if ( car & bit5 )
	  P5_ON;
	else
		P5_OFF;
	if ( car & bit4 )
	  P4_ON;
	else
		P4_OFF;	
	E_OFF;	// valide commande sur front descendant	
	Delay(10000);	 // 37 [us]			
}
// CHANGE L'ADRESSE DDRAM 
// 2x16 -> ligne 1 commence a 0x00, ligne 2 commence a 0x40
// 4 lignes: 0x00, 0x40, 0x14, 0x54  (a verifier)
void line_feed()
{
	RS_OFF;	// Commande
	E_ON;		// arme
	P7_ON;
	P6_ON;
	P5_OFF;  
	P4_OFF;	 
	E_OFF;	// valide commande sur front descendant
	//Delay(100000); // 37 us	E_ON; 	// arme
  E_ON; 	// arme
	P7_OFF;	
	P6_OFF;	 
	P5_OFF; 
	P4_OFF; 
	E_OFF; // front descendant -> valide commande
	Delay(100000);	 // 37 [us]		
}

void lcd_init()
{
  function_set();
  entry_mode_set();
  display_on_off_control();	
	//cursor_display_shift();
	//clear_display();
}
// CURSOR & DISPLAY SHIFTS : direction deplacement curseur et affichage
void cursor_display_shift(void)
{
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;  
	P4_ON;	// commande Cursor/Display Shift 
	E_OFF;	// valide commande sur front descendant
	//Delay(100000); // 37 us	E_ON; 	
  E_ON; 	// arme
	P7_OFF;	// Cursor-move or Display-shift: OFF = Move cursor, ON = shift display
	P6_OFF;	// Shift Direction: OFF = Shift Left, ON = Shift Right 
	P5_OFF; // n/a
	P4_OFF; // n/a
	E_OFF; // front descendant -> valide commande
	Delay(100000);	 // 37 [us]		
}
// ENTRY MODE SET : direction deplacement curseur et du shift du display pendant ecriture/lecture donnee
void entry_mode_set(void)
{
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;  
	P4_OFF; 
	E_OFF;	// valide commande sur front descendant
	//Delay(100000); // 37 us
	E_ON; 	// arme
	P7_OFF;  
	P6_ON;  // commande Entry Mode Set (effet si P5 ON & P4 OFF ou P5 OFF & P4 ON)
	P5_ON;	// Cursor Move Direction, OFF = decremente position curseur, ON = incremente position curseur  
	P4_OFF;	// Display Shift, OFF = pas de shift du display, ON = shift du display
	E_OFF; // front descendant -> valide commande
	Delay(100000);	 // 37 [us]		
}
// FUNCTION SET: longueur de donnees pour l'interface, nombre de lignes, fonte caracteres
void function_set(void)
{
	// DATA INTERFACE LENGTH = 4 bits -> il faut envoyer 0x28 0b00101000 -> on envoie 0010, puis 1000 decale de 4
	RS_OFF;	// commande
	E_ON;		// arme pour bits poids fort
	P7_OFF;
	P6_OFF;
	P5_ON;  // Commande Function Set
	P4_OFF; // Interface 4 bits
	E_OFF;	// valide commande sur front descendant
	//Delay(100000); // 37 us
	E_ON; 	// arme pour bits poifs faible
	P7_ON;	// 2 lignes
	P6_OFF;	// OFF = 5x7 dots, ON = 5x10 dots, ! si ON 5x10 empiete sur la ligne en-dessous
	P5_OFF; // n/a
	P4_OFF; // n/a
	E_OFF; // front descendant -> valide commande
	Delay(100000);	 // 37 [us]
}
// DISPLAY CONTROL
void display_on_off_control()
{
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;  
	P4_OFF; 
	E_OFF;	// valide commande sur front descendant
	//Delay(100000); // 37 us
	E_ON; 	// arme
	P7_ON;  // Commande Display Control 
	P6_ON;	// ON = display ON, OFF = display OFF
	P5_ON;	// ON = cursor ON, OFF = cursor OFF
	P4_ON;	// ON = cursor blink, OFF = no blink, juste souligne fixe
	E_OFF; // front descendant -> valide commande
	Delay(100000);	 // 37 [us]	
}
// CURSOR HOME (pas d'effacement de l'afficheur)
void cursor_home(void)
{
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;  
	P4_OFF; 
	E_OFF;	// valide commande sur front descendant
	//Delay(10000);  
	E_ON; 	// arme
	P7_OFF;  
	P6_OFF; 
	P5_ON;  // commande Cursor Home
	P4_OFF; // n/a
	E_OFF; // front descendant -> valide commande
	Delay(1000000);	 // ! 1.52 [ms]		
}
// CLEAR DISPLAY (efface afficheur et retour home = adresse 0)
void clear_display(void) 
{
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;  
	P4_OFF; 
	E_OFF;	// valide commande sur front descendant
	//Delay(10000); 
	E_ON; 	// arme
	P7_OFF;  
	P6_OFF; 
	P5_OFF; 
	P4_ON; // commande Clear Cisplay
	E_OFF; // front descendant -> valide commande
	Delay(1000000);	 // ! 1.52 [ms]		
}
void Delay(int d)
{
	int i;
	for(i=0; i < d; i++)
	;
}


void init_old(void)
{
	// DATA INTERFACE LENGTH = 4 bits
	// il faut envoyer 0x28 0b00101000
	// -> on envoie 0010, puis 1000 decale de 4
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_ON;
	P4_OFF; // 4 bits
	E_OFF;	// valide commande sur front descendant
	//Delay(10000);
	E_ON; 	// arme
	P7_ON;  // 2 lignes
	P6_OFF; // 5x7 dots
	P5_OFF; // n/a
	P4_OFF; // n/a
	E_OFF; // front descendant -> valide commande
	Delay(100000);
	
	// CLEAR DISPLAY
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;
	P4_OFF;
	E_OFF;	// envoie commande sur front descendant
	//Delay(10000);
	E_ON; 	// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;
	P4_ON;
	E_OFF; // front descendant -> envoie
	Delay(10000000);

		// ENTRY MODE SET
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;  
	P4_OFF; 
	E_OFF;	// valide commande sur front descendant
	//Delay(10000); // 37 us
	E_ON; 	// arme
	P7_OFF;  
	P6_OFF;  // commande Entry Mode Set
	P5_ON; 	// Cursor Move Direction, OFF = decremente position curseur, ON = incremente position curseur  
	P4_OFF;	// Display Shift, OFF = pas de shift du display, ON = shift du display
	E_OFF; // front descendant -> valide commande
	Delay(1000000);	 // 37 [us]	

	// DISPLAY AND CURSOR CONTROL
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;
	P4_OFF;
	E_OFF;	// envoie commande sur front descendant
//	Delay(10000);
	E_ON; 	// arme
	P7_ON;  // DISPLAY AND CURSOR CONTROL
	P6_ON;  // Display ON
	P5_ON;  // 
	P4_ON;  // ON = cursor clignote, OFF = pas de cursor
	E_OFF; // front descendant -> envoie
	Delay(100000);

/*
	// CLEAR DISPLAY
	RS_OFF;	// commande
	E_ON;		// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;
	P4_OFF;
	E_OFF;	// envoie commande sur front descendant
	Delay(10000);
	E_ON; 	// arme
	P7_OFF;
	P6_OFF;
	P5_OFF;
	P4_ON;
	E_OFF; // front descendant -> envoie
	Delay(100000);
	*/
}


